package elijah.base.dialog;

import android.content.Context;
import android.util.Log;
import android.view.animation.AnimationUtils;
import android.widget.TextView;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.collection.ArraySet;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;

import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BasePopupView;
import com.lxj.xpopup.core.CenterPopupView;
import com.lxj.xpopup.interfaces.XPopupCallback;
import com.lxj.xpopup.util.XPopupUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import elijah.base.R;
import elijah.base.adapter.BaseSimpleAdapter;
import elijah.base.databinding.BaseViewItemMultiSelectBinding;
import elijah.base.dialog.api.OnItemMultiSelectCallback;
import elijah.base.net.BaseResult;
import elijah.base.result.ListResult;
import elijah.base.utils.DensityUtils;
import elijah.base.utils.DialogUtils;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class BaseItemMultiSelectView<T, V extends ViewBinding> extends CenterPopupView {


    private Builder<T, V> builder;
    private BasePopupView dialog;
    private int page = 0;
    BaseViewItemMultiSelectBinding binding;


    private BaseItemMultiSelectView(@NonNull Context context) {
        super(context);
    }


    @Override
    protected int getImplLayoutId() {
        return R.layout.base_view_item_multi_select;
    }

    @Override
    protected void onCreate() {
        super.onCreate();
        binding = BaseViewItemMultiSelectBinding.bind(getPopupImplView());
        buildView();
        getData(page = 0);


    }

    public BaseItemMultiSelectView<T, V> show(Builder<T, V> builder) {
        this.builder = builder;
        showDialog();
        return this;
    }

    private void getData(int page) {
        builder.getDataObservable().getData(binding.etSearch.getText().toString(), page)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseResult<ListResult<T>>(getContext(), false) {
                    @Override
                    public void onSubscribe(Disposable d) {
                        super.onSubscribe(d);
                        removeCallbacks(stopAnim);
                        binding.btRefresh.clearAnimation();
                        binding.btRefresh.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.rotate_anim));
                    }

                    @Override
                    public void onSuccess(ListResult<T> tListResult) {
                        postDelayed(stopAnim, 800);
                        super.onSuccess(tListResult);
                    }


                    @Override
                    public void onError(Throwable e) {
                        postDelayed(stopAnim, 800);
                        super.onError(e);
                    }

                    @Override
                    public void success(ListResult<T> tListResult) {
                        builder.getDataAdapter().setData(tListResult.getValues());
                        builder.getDataAdapter().getSelection().clear();

                        if (builder.getDataCallback() != null) {
                            builder.getDataCallback().onData(BaseItemMultiSelectView.this, tListResult.getValues());
                        }
                        binding.tvEmpty.setVisibility(tListResult.getValues().size() > 0 ? GONE : VISIBLE);
                    }
                });
    }

    public TextView getTitleTextView() {
        return binding.title;
    }

    private final Runnable stopAnim = () -> binding.btRefresh.clearAnimation();


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        removeCallbacks(stopAnim);
    }

    private void buildView() {

        binding.btClose.setOnClickListener(view -> DialogUtils.dismiss(dialog));
        binding.btRefresh.setOnClickListener(view -> getData(page));

        binding.title.setText(builder.getTitle());
        if (builder.getHeaderRes() > 0) {
            binding.headerContainer.addView(inflate(getContext(), builder.getHeaderRes(), null));
        } else {
            binding.headerContainer.setVisibility(GONE);
        }


        binding.btSearch.setVisibility(builder.isSearchable() ? VISIBLE : GONE);
        binding.etSearch.setVisibility(builder.isSearchable() ? VISIBLE : GONE);


        binding.btnCancel.setOnClickListener(v -> dismiss());
        if (builder.getOnItemMultiSelectCallback() != null) {
            binding.btnSubmit.setOnClickListener(v -> {
                List<T> selects = new ArrayList<>(builder.getDataAdapter().selection.size());
                for (Integer integer : builder.getDataAdapter().selection) {
                    selects.add(builder.getDataAdapter().getItem(integer));
                }
                builder.getOnItemMultiSelectCallback().onSelect(selects);
                dialog.dismiss();

            });

        }
        binding.btAll.setVisibility(builder.getOnNothingSelectClickListener() != null ? VISIBLE : GONE);
        if (builder.getOnNothingSelectClickListener() != null) {
            binding.btAll.setOnClickListener(view -> {
                builder.getOnNothingSelectClickListener().onClick(view);
                dialog.dismiss();
            });
        }

        if (builder.getOnActionClickCallback() != null) {
            binding.btAction.setVisibility(VISIBLE);
            binding.btAction.setText(builder.getActionName());
            binding.btAction.setOnClickListener(v -> builder.getOnActionClickCallback().onAction(BaseItemMultiSelectView.this));
        }

        binding.recyclerView.setAdapter(builder.getDataAdapter());
        binding.recyclerView.setLayoutManager(builder.getLayoutManager() != null ? builder.getLayoutManager() : new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
        if (builder.getLayoutManager() == null)
            binding.recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));

        binding.btSearch.setOnClickListener(view -> getData(page = 0));
        binding.btAdd.setVisibility(builder.getOnAddActionClickCallback() != null ? VISIBLE : GONE);
        binding.btAdd.setOnClickListener(view -> {
            if (builder.getOnAddActionClickCallback() != null) {
                builder.getOnAddActionClickCallback().onAction(this);
            }
        });

    }


    private void showDialog() {
        dialog = new XPopup.Builder(getContext())
                .popupWidth(DensityUtils.getWidthPxRatio(builder.getViewWidth()))
                .popupHeight(builder.isAutoMinHeight() ? 0 : XPopupUtils.getScreenHeight(getContext()) - XPopupUtils.getStatusBarHeight() - XPopupUtils.getNavBarHeight())
                .autoDismiss(builder.isAutoDismiss())
                .dismissOnTouchOutside(builder.isAutoDismiss())
                .setPopupCallback(builder.popupCallback != null ? builder.popupCallback : new BasePopupCallback() {
                })
                .hasNavigationBar(false)
                .hasStatusBar(false)
                .asCustom(this)
                .show();
    }


    public static class Builder<T, V extends ViewBinding> {
        private final Context context;
        private String title;
        @IdRes
        private int headerRes;
        private float viewWidth = 0.5f;
        private boolean searchable;
        private String actionName;
        private boolean autoDismiss;
        private boolean autoMinHeight;
        private DataObservable<T> dataObservable;
        private MultiSelectAdapter<T, V> dataAdapter;


        private LinearLayoutManager layoutManager;
        private OnItemMultiSelectCallback<T> onItemMultiSelectCallback;
        private OnAddActionClickCallback<T> onAddActionClickCallback;
        private OnActionClickCallback<T> onActionClickCallback;
        private OnClickListener onNothingSelectClickListener;
        private DataCallback<T> dataCallback;
        private XPopupCallback popupCallback;


        public MultiSelectAdapter<T, V> getDataAdapter() {
            return dataAdapter;
        }

        public Builder<T, V> setDataAdapter(MultiSelectAdapter<T, V> dataAdapter) {
            this.dataAdapter = dataAdapter;
            return this;
        }


        public XPopupCallback getPopupCallback() {
            return popupCallback;
        }

        public Builder<T, V> setPopupCallback(XPopupCallback popupCallback) {
            this.popupCallback = popupCallback;
            return this;
        }


        public DataCallback<T> getDataCallback() {
            return dataCallback;
        }

        public Builder<T, V> setDataCallback(DataCallback<T> dataCallback) {
            this.dataCallback = dataCallback;
            return this;
        }

        public boolean isAutoDismiss() {
            return autoDismiss;
        }

        public Builder<T, V> setAutoDismiss(boolean autoDismiss) {
            this.autoDismiss = autoDismiss;
            return this;
        }

        public boolean isAutoMinHeight() {
            return autoMinHeight;
        }

        public Builder<T, V> setAutoMinHeight(boolean autoMinHeight) {
            this.autoMinHeight = autoMinHeight;
            return this;
        }


        public OnClickListener getOnNothingSelectClickListener() {
            return onNothingSelectClickListener;
        }

        public Builder<T, V> setOnNothingSelectClickListener(OnClickListener onNothingSelectClickListener) {
            this.onNothingSelectClickListener = onNothingSelectClickListener;
            return this;
        }

        public LinearLayoutManager getLayoutManager() {
            return layoutManager;
        }

        public Builder<T, V> setLayoutManager(LinearLayoutManager layoutManager) {
            this.layoutManager = layoutManager;
            return this;
        }

        public OnItemMultiSelectCallback<T> getOnItemMultiSelectCallback() {
            return onItemMultiSelectCallback;
        }

        public Builder<T, V> setOnItemMultiSelectCallback(OnItemMultiSelectCallback<T> onItemMultiSelectCallback) {
            this.onItemMultiSelectCallback = onItemMultiSelectCallback;
            return this;
        }


        public OnAddActionClickCallback<T> getOnAddActionClickCallback() {
            return onAddActionClickCallback;
        }

        public Builder<T, V> setOnAddActionClickCallback(OnAddActionClickCallback<T> onAddActionClickCallback) {
            this.onAddActionClickCallback = onAddActionClickCallback;
            return this;
        }

        public Builder<T, V> setOnActionClickCallback(String actionName, OnActionClickCallback<T> onActionClickCallback) {
            this.onActionClickCallback = onActionClickCallback;
            this.actionName = actionName;
            return this;
        }

        public OnActionClickCallback<T> getOnActionClickCallback() {
            return onActionClickCallback;
        }

        public String getActionName() {
            return actionName;
        }

        public boolean isSearchable() {
            return searchable;
        }

        public Builder<T, V> setSearchable(boolean searchable) {
            this.searchable = searchable;
            return this;
        }


        public Builder(Context context) {
            this.context = context;
        }

        public BaseItemMultiSelectView<T, V> show() {
            return new BaseItemMultiSelectView<T, V>(context) {
            }.show(this);
        }


        public String getTitle() {
            return title;
        }

        public Builder<T, V> setTitle(String title) {
            this.title = title;
            return this;
        }

        public DataObservable<T> getDataObservable() {
            return dataObservable;
        }

        public Builder<T, V> setDataObservable(DataObservable<T> dataObservable) {
            this.dataObservable = dataObservable;
            return this;
        }

        public float getViewWidth() {
            return viewWidth;
        }

        public Builder<T, V> setViewWidth(float viewWidth) {
            this.viewWidth = viewWidth;
            return this;
        }


        public int getHeaderRes() {
            return headerRes;
        }

        public Builder<T, V> setHeaderRes(int headerRes) {
            this.headerRes = headerRes;
            return this;
        }


    }

    public interface DataObservable<T> {
        Single<ListResult<T>> getData(String key, int page);
    }


    public interface DataAdapter<T, V extends ViewBinding> {
        BaseSimpleAdapter<T, V> getAdapter(Set<Integer> selection);
    }

    public interface OnAddActionClickCallback<T> {
        void onAction(BaseItemMultiSelectView<?, ?> baseView);
    }

    public interface OnActionClickCallback<T> {
        void onAction(BaseItemMultiSelectView<?, ?> baseView);
    }

    public void refreshData() {
        getData(page = 0);
    }

    public interface DataCallback<T> {
        void onData(BaseItemMultiSelectView<?, ?> view, List<T> values);
    }

    public static abstract class MultiSelectAdapter<T, V extends ViewBinding> extends BaseSimpleAdapter<T, V> {
        private final Set<Integer> selection = new ArraySet<>();

        public MultiSelectAdapter() {

        }

        public Set<Integer> getSelection() {
            return selection;
        }

        @Override
        public void setData(V holder, T value, int position) {
            holder.getRoot().setOnClickListener(v1 -> {
                if (selection.contains(position)) {
                    selection.remove(position);
                } else {
                    selection.add(position);
                }
                notifyItemChanged(position);
            });
            holder.getRoot().setBackgroundColor(selection.contains(position) ? 0x33000000 : 0);
            setData(holder, value, position, selection);
        }

        public abstract void setData(V holder, T value, int position, Set<Integer> selection);
    }

}
